package com.xr.core.system.common.base;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonProperty.Access;
import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;

public class MyPage<T> implements IPage<T> {

    private static final long serialVersionUID = -8447987374288843989L;

    /**
     * 查询数据列表
     */
    protected List<T> records = Collections.emptyList();

    @Getter
    private long next;

    @Getter
    private long prev;

    public void setAscOrder(String... ascOrder) {
        for (String s : ascOrder) {
            orders.add(OrderItem.asc(s));
        }
    }

    public void setDescOrder(String... descOrder) {
        for (String s : descOrder) {
            orders.add(OrderItem.desc(s));
        }
    }

    /**
     * 总数
     */
    protected long total = 0;

    /**
     * 每页显示条数
     */
    protected long size = 10;

    /**
     * 当前页
     */
    protected long current = 1;

    /**
     * 排序字段信息
     */
    @Setter
    @JsonProperty(access = Access.WRITE_ONLY)
    protected List<OrderItem> orders = new ArrayList<>();

    /**
     * 自动优化 COUNT SQL
     */
    @JsonProperty(access = Access.WRITE_ONLY)
    protected boolean optimizeCountSql = true;

    /**
     * 是否进行 count 查询
     */
    @JsonProperty(access = Access.WRITE_ONLY)
    protected boolean searchCount = true;

    /**
     * optimizeJoinOfCountSql
     */
    @Setter
    protected boolean optimizeJoinOfCountSql = true;

    /**
     * countId
     */
    @Setter
    @JsonProperty(access = Access.WRITE_ONLY)
    protected String countId;

    /**
     * maxLimit
     */
    @Setter
    @JsonProperty(access = Access.WRITE_ONLY)
    protected Long maxLimit;

    public MyPage() {

    }

    /**
     * 分页构造函数
     *
     * @param current 当前页
     * @param size    每页显示条数
     */
    public MyPage(long current, long size) {
        this(current, size, 0);
    }

    public MyPage(long current, long size, long total) {
        this(current, size, total, true);
    }

    public MyPage(long current, long size, boolean searchCount) {
        this(current, size, 0, searchCount);
    }

    public MyPage(long current, long size, long total, boolean searchCount) {
        if (current > 1) {
            this.current = current;
        }
        this.size = size;
        this.total = total;
        this.searchCount = searchCount;
    }

    /**
     * 是否存在上一页
     *
     * @return true / false
     */
    public boolean hasPrevious() {
        return current > 1;
    }

    /**
     * 是否存在下一页
     *
     * @return true / false
     */
    public boolean hasNext() {
        return current < getPages();
    }

    @Override
    public List<T> getRecords() {
        return records;
    }

    @Override
    public MyPage<T> setRecords(List<T> records) {
        this.records = records;
        return this;
    }

    @Override
    public long getTotal() {
        return total;
    }

    @Override
    public MyPage<T> setTotal(long total) {
        this.total = total;
        next = hasNext() ? current + 1 : -1;
        prev = hasPrevious() ? current - 1 : -1;
        return this;
    }

    @Override
    public long getSize() {
        return size;
    }

    @Override
    public MyPage<T> setSize(long size) {
        this.size = size;
        return this;
    }

    @Override
    public long getCurrent() {
        return current;
    }

    @Override
    public MyPage<T> setCurrent(long current) {
        this.current = current;
        return this;
    }

    @Override
    public String countId() {
        return countId;
    }

    @Override
    public Long maxLimit() {
        return maxLimit;
    }

    /**
     * 查找 order 中正序排序的字段数组
     *
     * @param filter 过滤器
     * @return 返回正序排列的字段数组
     */
    private String[] mapOrderToArray(Predicate<OrderItem> filter) {
        List<String> columns = new ArrayList<>(orders.size());
        orders.forEach(i -> {
            if (filter.test(i)) {
                columns.add(i.getColumn());
            }
        });
        return columns.toArray(new String[0]);
    }

    /**
     * 移除符合条件的条件
     *
     * @param filter 条件判断
     */
    private void removeOrder(Predicate<OrderItem> filter) {
        for (int i = orders.size() - 1; i >= 0; i--) {
            if (filter.test(orders.get(i))) {
                orders.remove(i);
            }
        }
    }

    /**
     * 添加新的排序条件，构造条件可以使用工厂
     *
     * @param items 条件
     * @return 返回分页参数本身
     */
    public MyPage<T> addOrder(OrderItem... items) {
        orders.addAll(Arrays.asList(items));
        return this;
    }

    /**
     * 添加新的排序条件，构造条件可以使用工厂
     *
     * @param items 条件
     * @return 返回分页参数本身
     */
    public MyPage<T> addOrder(List<OrderItem> items) {
        orders.addAll(items);
        return this;
    }

    @Override
    public List<OrderItem> orders() {
        return orders;
    }

    @Override
    public boolean optimizeCountSql() {
        return optimizeCountSql;
    }

    public static <T> MyPage<T> of(long current, long size, long total, boolean searchCount) {
        return new MyPage<>(current, size, total, searchCount);
    }

    @Override
    public boolean optimizeJoinOfCountSql() {
        return optimizeJoinOfCountSql;
    }

    public MyPage<T> setSearchCount(boolean searchCount) {
        this.searchCount = searchCount;
        return this;
    }

    public MyPage<T> setOptimizeCountSql(boolean optimizeCountSql) {
        this.optimizeCountSql = optimizeCountSql;
        return this;
    }

    @Override
    public long getPages() {
        return IPage.super.getPages();
    }

    /* ---------------- 以下为静态构造方式 ---------------- */
    public static <T> MyPage<T> of(long current, long size) {
        return of(current, size, 0);
    }

    public static <T> MyPage<T> of(long current, long size, long total) {
        return of(current, size, total, true);
    }

    public static <T> MyPage<T> of(long current, long size, boolean searchCount) {
        return of(current, size, 0, searchCount);
    }

    @Override
    public boolean searchCount() {
        if (total < 0) {
            return false;
        }
        return searchCount;
    }

    /**
     * begin---------------- 未来抛弃移除的方法 ---------------- 该部分属性转移至 {@link PageDTO}
     */
    @Deprecated
    public String getCountId() {
        return countId;
    }

    @Deprecated
    public Long getMaxLimit() {
        return maxLimit;
    }

    @Deprecated
    public List<OrderItem> getOrders() {
        return orders;
    }

    @Deprecated
    public boolean isOptimizeCountSql() {
        return optimizeCountSql;
    }

    @Deprecated
    public boolean isSearchCount() {
        return searchCount;
    }
    /**
     * end---------------- 未来抛弃移除的方法 ---------------- 该部分属性转移至 {@link PageDTO}
     */

}
